<template>
  <div class="app-container">
    <div class="h-full flex">
      <div class="mr-4 h-full bg-white p-2">
        <el-tree
          ref="treeRef"
          :data="treeData"
          node-key="id"
          :props="defaultProps"
          highlight-current
          style="width: 220px"
          default-expand-all
          :expand-on-click-node="false"
          @node-click="handleNodeClick"
        >
          <template #default="{ node, data }">
            <div class="w-full flex justify-between items-center">
              <span>{{ data.label }}</span>

              <div v-if="data.type === 'folder'">
                <i class="el-icon-delete text-xs mr-2 el-button--text" @click.stop="deleteDirectory(data.label)"></i>
              </div>
              <div v-if="data.type === 'file'">
                <i
                  class="el-icon-delete text-xs mr-2 el-button--text"
                  @click.stop="deleteFile(data.folder, data.label)"
                ></i>
              </div>
            </div>
          </template>
        </el-tree>
      </div>

      <div class="h-full flex-1 flex flex-col">
        <div class="relative">
          <el-button type="primary" size="small" @click="openDialog">添加任务</el-button>
          <el-button
            type="primary"
            size="small"
            :disabled="!isFolderSelected"
            class=""
            style=""
            @click="handleClickRandomGroup"
          >
            添加随机组
          </el-button>
          <!-- <el-button type="primary" size="small" @click="handleClickAddRoute">添加路由</el-button> -->
        </div>
        <div class="flex-1 table-wrapper">
          <ag-grid-vue
            class="ag-theme-alpine"
            style="width: 100%; height: 100%; margin-top: 20px"
            :row-data="tableData"
            :column-defs="columnDefs"
            :grid-options="gridOptions"
            @grid-ready="onGridReady"
          >
          </ag-grid-vue>
        </div>
      </div>
    </div>

    <el-dialog :title="title" :visible.sync="dialogVisible" width="640px">
      <el-form label-width="120px">
        <el-form-item label="选择目录">
          <el-select v-model="formData.folder" placeholder="选择目录" class="w-full">
            <el-option v-for="folder in folderOptions" :key="folder" :label="folder" :value="folder"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="输入日期">
          <el-date-picker
            v-model="formData.date"
            type="date"
            placeholder="选择日期"
            value-format="yyyy-MM-dd"
            style="width: 100%"
          >
          </el-date-picker>
        </el-form-item>
        <el-form-item label="输入 JSON 内容">
          <div class="codemirror-container" style="line-height: 1.2">
            <codemirror v-model="formData.content" :options="options" />
          </div>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button size="small" @click="dialogVisible = false">取消</el-button>
        <el-button size="small" type="primary" @click="saveTask">保存</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import _ from 'lodash'
import Vue from 'vue'
import moment from 'moment'
import { codemirror } from 'vue-codemirror'
import 'codemirror/lib/codemirror.css'

import router from '@/router'

import {
  fetchTreeData,
  fetchFileData,
  fetchDirectoryData,
  deleteDirectory,
  deleteFile,
  deleteGroup,
  updateGroup,
  saveFileData
} from '@/api/group.js'

import { FOLDER_OPTIONS, randomFnMap, getMaxGroupNameWithDate, CODEMIRROR_OPTIONS } from '@/utils/study.js'

import { AgGridVue } from 'ag-grid-vue'
import 'ag-grid-community/styles/ag-grid.css' // 基础样式
import 'ag-grid-community/styles/ag-theme-alpine.css' // 主题样式

import ActionCellRenderer from '@/views/kit/components/ActionCellRenderer.vue'
import GroupDataCellRenderer from '@/views/kit/components/GroupDataCellRenderer.vue'

// 垂直居中样式
const verticalCenterStyle = { display: 'flex', alignItems: 'center' }

export default {
  name: 'RandomGroup',

  components: {
    codemirror,
    AgGridVue,
    // eslint-disable-next-line vue/no-unused-components
    ActionCellRenderer,
    // eslint-disable-next-line vue/no-unused-components
    GroupDataCellRenderer
  },

  data() {
    return {
      // 当前编辑的组
      editingGroup: null,
      // 表格高度
      tableHeight: null,
      // 树形数据
      treeData: [],
      // 表格数据
      tableData: [],
      // 弹窗显示状态
      dialogVisible: false,
      // 表单数据
      formData: {
        // 目录名称
        folder: '',
        // 日期
        date: '',
        // JSON 数据内容
        content: ''
      },
      // 目录选项
      folderOptions: FOLDER_OPTIONS,
      // 树形数据默认属性
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      // 动作
      action: null,
      // 当前是否选中目录
      isFolderSelected: false,
      // 当前选中的目录名称
      currentFolder: null,
      // 当前点击文件名称
      currentFile: '',
      // 是否正在生成随机组
      loading: false,
      // codemirror 配置
      options: CODEMIRROR_OPTIONS,
      // 表格列定义
      columnDefs: [
        { headerName: 'File Name', field: 'fileName', width: 200, cellStyle: verticalCenterStyle },
        { headerName: 'Group Name', field: 'groupName', width: 300, cellStyle: verticalCenterStyle },
        {
          headerName: 'Group Data',
          field: 'groupData',
          width: 1000,
          cellRenderer: (params) => {
            const vm = new Vue({
              render(h) {
                return h(GroupDataCellRenderer, {
                  props: { params }
                })
              }
            }).$mount()
            return vm.$el
          }
        },
        {
          // 添加操作栏
          headerName: 'Action',
          field: 'actions',
          // 设置操作栏宽度
          // width: 128,
          width: 128 + 128 / 2,
          // 固定列到右侧
          pinned: 'right',
          cellStyle: verticalCenterStyle,
          cellRenderer: (params) => {
            const _this = this
            const vm = new Vue({
              render(h) {
                return h(ActionCellRenderer, {
                  props: { params, copyConfig: { show: false }},
                  on: {
                    edit: (row) => {
                      _this.handleEdit(row)
                    },
                    delete: (row) => {
                      _this.handleDelete(row)
                    }
                  }
                })
              }
            }).$mount()
            return vm.$el
          }
        }
      ],
      // 表格配置
      gridOptions: {
        // 允许单元格文本选择
        enableCellTextSelection: true,
        // 行高
        // rowHeight: 25 * 40,
        // 默认布局，允许滚动条
        domLayout: 'normal'
      }
    }
  },

  computed: {
    // 返回 data 中所有属性的深拷贝
    dataCopy() {
      return JSON.parse(JSON.stringify(this.$data))
    },
    // 返回弹窗标题
    title() {
      return this.action === 'add' ? '添加任务' : '编辑任务'
    }
  },

  mounted() {
    this.fetchTreeData() // 初始化加载目录树数据
    this.setHeight() // 初始化设置表格高度
    window.addEventListener('resize', this.setHeight) // 窗口大小改变时动态调整高度
  },

  beforeDestroy() {
    window.removeEventListener('resize', this.setHeight) // 组件销毁时移除事件监听
  },

  methods: {
    // 网格表格初始化事件
    onGridReady(params) {
      this.gridApi = params.api
      this.gridColumnApi = params.columnApi

      // 调整列宽以适应容器
      // this.gridApi.sizeColumnsToFit()

      // console.log('gridApi', this.gridApi)

      // 窗口大小变化时调整表格宽度
      // window.addEventListener('resize', () => {
      //   this.gridApi.sizeColumnsToFit()
      // })
    },

    // 刷新选中目录的数据
    async refreshFolderData(folder) {
      try {
        const response = await fetchDirectoryData(folder)
        if (response.data.success) {
          const allData = response.data.data

          // 转换目录数据为表格展示格式
          const formattedData = allData.flatMap((item) => {
            const fileName = item.fileName
            const content = item.content

            return Object.entries(content).map(([groupName, groupData]) => ({
              groupName,
              groupData,
              fileName
            }))
          })

          this.tableData = formattedData // 更新表格数据
        } else {
          this.$message.error(`刷新目录数据失败：${folder}`)
        }
      } catch (error) {
        this.$message.error(`刷新目录数据失败：${folder}`)
        console.error(error)
      }
    },

    // 刷新选中文件的数据
    async refreshFileData(folder, file) {
      try {
        const response = await fetchFileData(folder, file)
        if (response.data.success) {
          this.transformData(response.data.data, file) // 更新表格数据
        } else {
          this.handleFileNotFound(folder, file) // 处理文件不存在的逻辑
        }
      } catch (error) {
        if (error.response && error.response.status === 404) {
          this.handleFileNotFound(folder, file) // 文件不存在时的处理
        } else {
          this.$message.error(`刷新文件数据失败：${file}`)
          console.error(error)
        }
      }
    },

    // 文件不存在时的处理
    handleFileNotFound(folder, file) {
      // 从树形数据中找到对应的父节点
      const parentNode = this.treeData.find((node) => node.label === folder)

      if (parentNode && parentNode.children) {
        // 在父节点的子节点中移除该文件
        parentNode.children = parentNode.children.filter((child) => child.label !== file)

        // 尝试选中下一个文件
        const nextNode = parentNode.children.find((child) => child.type === 'file')
        if (nextNode) {
          this.handleNodeClick(nextNode) // 选中下一个文件
          this.highlightNode(nextNode.id)
          return
        }
      }

      // 如果没有其他文件，清空表格数据并选中当前目录
      this.tableData = []
      this.isFolderSelected = true
      this.currentFile = null
      this.highlightNode(parentNode?.id) // 高亮父节点（目录）
    },

    // 删除目录及其内容（带二次确认）
    async deleteDirectory(folder) {
      try {
        await this.$confirm(`确定要删除目录 "${folder}" 及其内容吗？`, '确认删除', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        })

        const response = await deleteDirectory(folder)
        if (response.data.success) {
          this.$message.success(response.data.message)
          this.tableData = [] // 清空右侧表格数据

          // 如果当前删除的是选中的目录，重置状态
          if (this.currentFolder === folder) {
            this.isFolderSelected = false
            this.currentFolder = null
          }

          this.fetchTreeData() // 刷新目录树
        } else {
          this.$message.error('删除目录失败')
        }
      } catch (error) {
        if (error !== 'cancel') {
          this.$message.error('删除目录失败')
          console.error(error)
        }
      }
    },

    // 删除文件（带二次确认）
    async deleteFile(folder, file) {
      try {
        await this.$confirm(`确定要删除文件 "${file}" 吗？`, '确认删除', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        })

        const response = await deleteFile(folder, file)
        if (response.data.success) {
          this.$message.success(response.data.message)

          // 从树形数据中移除文件节点
          const parentNode = this.treeData.find((node) => node.label === folder)
          if (parentNode) {
            parentNode.children = parentNode.children.filter((child) => child.label !== file)
          }

          this.tableData = [] // 清空表格数据

          // 如果当前目录下没有文件，自动选中第一个目录
          if (parentNode?.children.length === 0) {
            this.isFolderSelected = true
            this.currentFile = null
            this.highlightNode(parentNode.id) // 高亮当前目录
          }
        } else {
          this.$message.error('删除文件失败')
        }
      } catch (error) {
        if (error !== 'cancel') {
          this.$message.error('删除文件失败')
          console.error(error)
        }
      }
    },
    // 动态设置表格高度
    setHeight() {
      this.tableHeight = document.querySelector('.table-wrapper').offsetHeight - 20
    },

    // 获取目录树数据
    async fetchTreeData() {
      try {
        const response = await fetchTreeData() // 调用后端接口获取树形数据
        if (response.data.success) {
          const treeData = response.data.data

          // 排序逻辑
          const folderOrderMap = FOLDER_OPTIONS.reduce((map, folder, index) => {
            map[folder] = index // 记录目录顺序
            return map
          }, {})

          const sortTreeData = (data) =>
            data
              .map((item) => {
                if (item.children && item.children.length > 0) {
                  item.children = sortTreeData(item.children) // 递归排序子节点
                }
                return item
              })
              .sort((a, b) => {
                const orderA = folderOrderMap[a.label] ?? Infinity // 获取排序索引，默认为 Infinity
                const orderB = folderOrderMap[b.label] ?? Infinity
                return orderA - orderB // 按索引排序
              })

          this.treeData = sortTreeData(treeData) // 更新排序后的树形数据

          // 自动选中第一个目录
          this.selectFirstFolder()
        } else {
          this.$message.error('获取目录树失败')
        }
      } catch (error) {
        this.$message.error('获取目录树失败')
        console.error(error)
      }
    },

    // 打开弹窗
    openDialog() {
      this.action = 'add'

      if (this.isFolderSelected) {
        // 当前选中的是目录
        this.formData.folder = this.currentFolder // 填充目录名称

        // 获取目录下文件的最新日期
        const parentNode = this.treeData.find((node) => node.label === this.currentFolder)
        if (parentNode && parentNode.children) {
          // 筛选出所有文件节点并获取日期
          const dates = parentNode.children
            .filter((child) => child.type === 'file') // 确认是文件
            .map((file) => {
              // 使用正则提取日期格式为 YYYY-MM-DD 的部分
              const match = file.label.match(/\d{4}-\d{2}-\d{2}/) // 匹配类似 "2025-01-24" 的日期格式
              return match ? match[0] : null // 如果匹配成功，返回日期部分，否则返回 null
            })
            .filter(Boolean) // 过滤掉 null 值

          // 获取最新的日期
          if (dates.length > 0) {
            const latestDate = dates.sort((a, b) => moment(b).diff(moment(a)))[0]
            this.formData.date = latestDate
          } else {
            this.formData.date = '' // 如果没有有效日期，保留为空
          }
        } else {
          this.formData.date = '' // 如果目录没有文件，保留为空
        }
      } else if (this.currentFile) {
        // 当前选中的是文件，尝试从文件名中提取日期
        const match = this.currentFile.match(/\d{4}-\d{2}-\d{2}/) // 匹配 YYYY-MM-DD 格式日期
        const extractedDate = match ? match[0] : '' // 如果匹配成功，返回日期部分，否则为空

        // 验证日期格式是否合法
        const isValidDate = moment(extractedDate, 'YYYY-MM-DD', true).isValid()
        this.formData.folder = this.currentFolder // 填充目录名称
        this.formData.date = isValidDate ? extractedDate : '' // 如果日期格式有效，则填充，否则为空
      } else {
        // 未选中文件或目录，默认为当前日期
        this.formData.folder = '' // 清空目录
        this.formData.date = moment().format('YYYY-MM-DD') // 填充当前日期
      }

      this.formData.content = '' // 清空 JSON 内容
      this.dialogVisible = true // 打开弹窗
    },

    // 点击树节点，加载文件或目录内容
    async handleNodeClick(node) {
      // 判断节点类型并执行对应逻辑
      if (node.type === 'file') {
        this.currentFile = node.label // 当前选中的文件
        this.currentFolder = node.folder // 文件所在目录
        this.isFolderSelected = false // 当前选中的不是目录

        // console.log('Selected file:', this.currentFile)
        // console.log('File belongs to folder:', this.currentFolder)

        try {
          const response = await fetchFileData(node.folder, node.label)
          if (response.data.success) {
            this.transformData(response.data.data, node.label) // 转换数据格式并更新表格
          } else {
            this.handleFileNotFound(node.folder, node.label) // 如果文件不存在，调用处理逻辑
          }
        } catch (error) {
          if (error.response && error.response.status === 404) {
            this.handleFileNotFound(node.folder, node.label) // 文件不存在
          } else {
            console.error('Error loading file:', error)
            this.$message.error(`加载文件失败：${node.label}`)
          }
        }
      } else if (node.type === 'folder') {
        this.currentFolder = node.label // 当前选中的目录
        this.currentFile = null // 清空当前文件
        this.isFolderSelected = true // 当前选中的是目录

        // console.log('Selected folder:', this.currentFolder)

        try {
          const response = await fetchDirectoryData(node.label)
          if (response.data.success) {
            const allData = response.data.data

            // 将目录数据转换为表格展示格式
            const formattedData = allData.flatMap((item) => {
              const fileName = item.fileName
              const content = item.content

              return Object.entries(content).map(([groupName, groupData]) => ({
                groupName,
                groupData,
                fileName
              }))
            })

            this.tableData = formattedData // 更新表格数据
          } else {
            this.$message.error(`加载目录失败：${node.label}`)
          }
        } catch (error) {
          console.error('Error loading folder:', error)
          this.$message.error(`加载目录失败：${node.label}`)
        }
      }

      // 高亮当前节点
      this.highlightNode(node.id)
    },

    // 转换目录中所有文件的数据为表格展示格式
    transformDataFromMultipleFiles(filesData) {
      const result = []
      filesData.forEach((fileData) => {
        const fileName = fileData.fileName // 提取文件名
        const content = fileData.content // 文件内容
        _.forEach(content, (groups, groupName) => {
          result.push({
            groupName, // 分组名称
            groupData: groups, // 分组数据
            fileName // 文件名
          })
        })
      })
      this.tableData = result // 更新表格数据
      console.log('表格数据:', result) // 调试输出
    },

    // 转换后端返回的数据为表格展示所需格式
    transformData(data, fileName) {
      const result = []
      _.forEach(data, (groups, groupName) => {
        result.push({
          groupName,
          groupData: groups,
          fileName // 添加文件名到每行数据
        })
      })
      this.tableData = result // 更新表格数据
    },

    // 删除表格行数据并刷新表格
    async handleDelete(row) {
      try {
        const folder = this.currentFolder // 当前目录
        const file = row.fileName // 当前文件名
        const groupName = row.groupName // 分组名称

        if (!folder || !file || !groupName) {
          this.$message.error('删除失败：目录、文件或分组名称缺失')
          return
        }

        // 确认删除
        await this.$confirm(`确定要删除组 "${groupName}" 吗？`, '确认删除', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        })

        // 调用后端接口删除
        const response = await deleteGroup(folder, file, groupName)

        if (response.data.success) {
          this.$message.success(response.data.message)

          // 根据当前选中的节点类型刷新表格数据
          if (this.currentFile) {
            // 如果选中的是文件，刷新该文件的数据
            await this.refreshFileData(folder, file)
          } else if (this.isFolderSelected) {
            // 如果选中的是目录，刷新整个目录的数据
            await this.refreshFolderData(folder)
          }
        } else {
          this.$message.error('删除失败')
        }
      } catch (error) {
        if (error !== 'cancel') {
          this.$message.error('删除失败')
          console.error(error)
        }
      }
    },

    // 编辑表格行数据
    handleEdit(row) {
      this.action = 'edit'

      if (!this.currentFile && !row.fileName) {
        this.$message.error('当前未选中文件，无法编辑分组！')
        return
      }

      this.dialogVisible = true

      // 填充编辑表单数据
      this.editingGroup = row.groupName // 当前正在编辑的组
      this.currentFile = this.currentFile || row.fileName
      this.formData.folder = this.currentFolder // 当前目录
      this.formData.date = row.fileName.split('-').slice(0, 3).join('-') // 提取日期
      this.formData.content = JSON.stringify(row.groupData, null, 2) // 将分组数据填充到表单
    },

    // 保存编辑后的数据
    async saveTask() {
      if (this.action === 'add') {
        // 如果没有编辑组，直接走新增逻辑
        await this.addNewGroup()
        return
      }

      let newGroupData
      try {
        newGroupData = JSON.parse(this.formData.content)
      } catch (error) {
        this.$message.error('JSON 数据格式错误，请输入合法的 JSON 数据')
        return
      }

      // 判断是否是空数组 [] 或嵌套空数组 [[], [], ...]
      if (
        Array.isArray(newGroupData) &&
        (newGroupData.length === 0 || newGroupData.every((item) => Array.isArray(item) && item.length === 0))
      ) {
        this.$message.warning('内容不能是空数组 [] 或嵌套空数组 [[], [], ...]，请填写有效的 JSON 数据！')
        return
      }

      try {
        this.loading = true // 启用按钮 loading 防止重复点击
        const response = await updateGroup(this.formData.folder, this.currentFile, this.editingGroup, newGroupData)

        if (response.data.success) {
          this.$message.success(response.data.message)

          // 根据当前选中的节点刷新表格数据
          if (this.currentFile) {
            await this.refreshFileData(this.currentFolder, this.currentFile)
          } else if (this.isFolderSelected) {
            await this.refreshFolderData(this.currentFolder)
          }

          // 关闭弹窗并清空状态
          this.dialogVisible = false
          this.editingGroup = null
        } else {
          this.$message.error('编辑组失败')
        }
      } catch (error) {
        console.log(error)
        this.$message.error('编辑组失败')
        console.error(error)
      } finally {
        this.loading = false // 结束按钮 loading 状态
      }
    },

    // 新增组数据
    async addNewGroup() {
      const { folder, date, content } = this.formData

      if (!folder || !date || !content) {
        this.$message.warning('请填写完整的任务信息')
        return
      }

      let jsonData
      try {
        jsonData = JSON.parse(content)
      } catch (error) {
        this.$message.error('JSON 数据格式错误，请输入合法的 JSON 数据')
        return
      }

      // 判断是否是空对象 {}
      if (Object.prototype.toString.call(jsonData) === '[object Object]' && Object.keys(jsonData).length === 0) {
        this.$message.warning('内容不能为空对象 {}，请填写有效的 JSON 数据！')
        console.warn('内容为空对象:', jsonData) // 调试日志
        return
      }

      try {
        this.loading = true
        const response = await saveFileData(folder, date, jsonData)
        if (response.data.success) {
          this.$message.success(response.data.message)
          this.dialogVisible = false // 关闭弹窗
          this.fetchTreeData() // 刷新目录树
        } else {
          this.$message.error('保存任务失败: ' + response.data.message)
        }
      } catch (error) {
        if (error.response && error.response.data) {
          this.$message.error(`${error.response.data.message || '未知错误'}`)
        } else {
          this.$message.error('保存任务失败: 网络错误或服务器无响应')
        }
      } finally {
        this.loading = false
      }
    },

    // 添加随机组
    handleClickRandomGroup() {
      if (!this.isFolderSelected) {
        this.$message.warning('请选择目录')
        return
      }
      const fn = randomFnMap[this.currentFolder]
      if (!fn) {
        this.$message.warning('请开发随机生成函数')
        return
      }

      // console.log(this.tableData)
      const maxGroup = getMaxGroupNameWithDate(this.tableData)
      console.log(maxGroup)

      const startIndex = maxGroup == null ? 1 : maxGroup.maxNumber + 1

      const historicalData = _.flatMap(this.tableData, (item) => item.groupData)

      // const result = fn(startIndex, 500, 8, historicalData)
      const result = fn(startIndex, 10, 8, historicalData)

      this.formData.folder = this.currentFolder
      this.formData.content = JSON.stringify(result, null, 2)
      this.formData.date = maxGroup.date
      this.dialogVisible = true
    },

    // 自动高亮指定节点
    highlightNode(nodeKey) {
      this.$nextTick(() => {
        this.$refs.treeRef.setCurrentKey(nodeKey) // 设置当前选中节点
      })
    },

    // 选中第一个目录并加载其数据
    selectFirstFolder() {
      const firstNode = this.treeData[0] // 获取第一个目录
      if (firstNode && firstNode.type === 'folder') {
        this.handleNodeClick(firstNode) // 模拟点击第一个目录
        this.highlightNode(firstNode.id) // 高亮第一个目录
      }
    },

    // 添加路由
    handleClickAddRoute() {
      router.addRoutes([
        {
          path: '/kit',
          component: () => import('@/layout'),
          meta: {
            title: 'kit',
            icon: 'line-chart'
          },
          children: [
            {
              path: 'test',
              component: () => import('@/views/kit/random-group'),
              name: 'kit' + 'Test',
              meta: {
                title: 'test',
                noCache: true
              }
            }
          ]
        }
      ])

      // router.addRoutes([{
      //   path: '/kit/test',
      //   component: () => import('@/views/kit/random-group'),
      //   name: 'kit' + 'Test',
      //   meta: {
      //     title: 'test',
      //     noCache: true
      //   }
      // }])
    }
  }
}
</script>
